package com.fosun.spr.plugin.shiro;

import java.util.LinkedHashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.fosun.spr.plugin.shiro.api.service.UucLoginService;
import com.fosun.spr.plugin.shiro.api.service.model.ListUrlPrivilegesSpModel;
import com.fosun.spr.plugin.shiro.api.service.model.ListUrlPrivilegesSrModel;

@Configuration
public class ShiroConfig {
	@Resource
	private UucLoginService uucLoginService;
	
    @Value("${spring.redis.shiro.host}")  
    private String host;  
    @Value("${spring.redis.shiro.port}")  
    private int port;  
    @Value("${spring.redis.shiro.timeout}")  
    private int timeout;  
    @Value("${spring.redis.shiro.password}")  
    private String password;  
    
	/**
	 * ShiroFilterFactoryBean 处理拦截资源文件问题。 注意：单独一个ShiroFilterFactoryBean配置是或报错的，以为在
	 * 初始化ShiroFilterFactoryBean的时候需要注入：SecurityManager
	 *
	 * Filter Chain定义说明 1、一个URL可以配置多个Filter，使用逗号分隔 2、当设置多个过滤器时，全部验证通过，才视为通过
	 * 3、部分过滤器可指定参数，如perms，roles
	 *
	 */
	@Bean
	public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

		// 必须设置 SecurityManager
		shiroFilterFactoryBean.setSecurityManager(securityManager);

		// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
		shiroFilterFactoryBean.setLoginUrl("/api/uucLogin/needLoginError");
		// 登录成功后要跳转的链接
		//shiroFilterFactoryBean.setSuccessUrl("/index");
		// 未授权界面;
		shiroFilterFactoryBean.setUnauthorizedUrl("/api/uucLogin/needLoginError");

		// 拦截器.
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
		// 配置不会被拦截的链接 顺序判断
		filterChainDefinitionMap.put("/api/uucLogin/**", "anon");

		// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
		//filterChainDefinitionMap.put("/api/uucLogin/submitLogout", "logout");
		filterChainDefinitionMap.put("/logout", "logout");
		
//		filterChainDefinitionMap.put("/api/uucUser/*", "perms[SPR_UUC_USER]");
//		filterChainDefinitionMap.put("/api/uucMenu/*", "perms[SPR_UUC_MENU]");
		
		ListUrlPrivilegesSpModel spModel2 = new ListUrlPrivilegesSpModel();
		ListUrlPrivilegesSrModel srModel2 =  uucLoginService.listUrlPrivileges(spModel2);
		ListUrlPrivilegesSrModel.Datas[] ds = srModel2.getDatas();
		if(ds!=null){
			for(int i=0,j=ds.length;i<j;i++) {
				filterChainDefinitionMap.put(ds[i].getUrlPattern(), "perms["+ds[i].getPrivilegeCode()+"]");
			}
		}

		// <!-- 过滤链定义，从上向下顺序执行，一般将 /**放在最为下边 -->:这是一个坑呢，一不小心代码就不好使了;
		// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
		filterChainDefinitionMap.put("/**", "user");

		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		System.out.println("Shiro拦截器工厂类注入成功");
		return shiroFilterFactoryBean;
	}

	@Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		// 设置realm.
		securityManager.setRealm(myShiroRealm());	
        // 自定义session管理 使用redis  
        securityManager.setSessionManager(sessionManager());  
        // 自定义缓存实现 使用redis  
        //securityManager.setCacheManager(cacheManager());  
		return securityManager;
	}

	/**
	 * 身份认证realm; (这个需要自己写，账号密码校验；权限等)
	 * 
	 * @return
	 */
	@Bean
	public MyShiroRealm myShiroRealm() {
		MyShiroRealm myShiroRealm = new MyShiroRealm();
		return myShiroRealm;
	}
	
    /**
     * 开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
    	System.out.println("authorizationAttributeSourceAdvisor");
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
 
    
    //自定义sessionManager  
    @Bean  
    public SessionManager sessionManager() {  
        MySessionManager mySessionManager = new MySessionManager();  
        mySessionManager.setSessionDAO(redisSessionDAO());  
        return mySessionManager;  
    }      
    /** 
     * RedisSessionDAO shiro sessionDao层的实现 通过redis 
     * <p> 
     * 使用的是shiro-redis开源插件 
     */  
    @Bean  
    public RedisSessionDAO redisSessionDAO() {  
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();  
        redisSessionDAO.setRedisManager(redisManager());  
        return redisSessionDAO;  
    }  
    /** 
     * 配置shiro redisManager 
     * <p> 
     * 使用的是shiro-redis开源插件 
     * 
     * @return 
     */  
    public RedisManager redisManager() {  
        RedisManager redisManager = new RedisManager();  
        redisManager.setHost(host);  
        redisManager.setPort(port);  
        redisManager.setExpire(1800);// 配置缓存过期时间  
        redisManager.setTimeout(timeout);  
        redisManager.setPassword(password);  
        return redisManager;  
    }  
    
    /** 
     * cacheManager 缓存 redis实现 
     * <p> 
     * 使用的是shiro-redis开源插件 
     * 
     * @return 
     */  
    @Bean  
    public RedisCacheManager cacheManager() {  
        RedisCacheManager redisCacheManager = new RedisCacheManager();  
        redisCacheManager.setRedisManager(redisManager());  
        return redisCacheManager;  
    }  
}
